﻿using System;
using System.Collections;

namespace InDepth2Demo.Chapter6
{
    /// <summary>
    /// 6.1 C#1 手写迭代器的痛苦
    /// </summary>
    public class HandwrittenIterator
    {
        public static void Call()
        {
            object[] values = { "a", "b", "c", "d", "e" };
            IterationSample collection = new IterationSample(values, 3);
            foreach (object x in collection)
            {
                Console.WriteLine(x);
            }
        }
    }

    public class IterationSample : IEnumerable
    {
        public object[] values;
        public int startingPoint;

        public IterationSample(object[] values, int startingPoint)
        {
            this.values = values;
            this.startingPoint = startingPoint;
        }

        // C# 1
        //public IEnumerator GetEnumerator()
        //{
        //    //throw new NotImplementedException();
        //    return new IterationSampleIterator(this);     //在 IterationSample 中实现 IEnumerable 接口
        //}

        // C# 2: 利用 yield 语句简化迭代器
        public IEnumerator GetEnumerator()
        {
            for (int index = 0; index < values.Length; index++)
            {
                Console.WriteLine($"GetEnumerator: {index}");                   // 每次调用时index不是从0开始的，而是从上一次的值开始的。
                yield return values[(index + startingPoint) % values.Length];
            }
        }
    }

    /// <summary>
    /// 嵌套类实现集合迭代器
    /// </summary>
    public class IterationSampleIterator : IEnumerator
    {
        IterationSample parent; //正在迭代的集合
        int position;           //遍历到的位置

        internal IterationSampleIterator(IterationSample parent) //internal？
        {
            this.parent = parent;
            position = -1;          //在第一个元素开始之前开始
        }

        bool IEnumerator.MoveNext()
        {
            if (position != parent.values.Length) //如果仍要遍历，那么增加position
            {
                position++;
            }
            return position < parent.values.Length;
        }

        public object Current       // 同 object IEnumerator.Current
        {
            get
            {
                if (position == -1 || position == parent.values.Length)//防止访问第一个元素之前的最后一个元素之后
                {
                    throw new InvalidOperationException();
                }
                int index = position + parent.startingPoint;    //
                index = index % parent.values.Length;           //
                return parent.values[index];                    // 实现封装
            }
        }

        void IEnumerator.Reset()
        {
            position = -1;  //返回第一个元素之前
        }
    }
}
